package com.ipan.jfinal.simpleApi;

import java.io.File;
import java.util.List;
import java.util.Map;

import com.ipan.jfinal.controller.ResultDefineManager;
import com.ipan.jfinal.render.MyCaptchaRender;
import com.ipan.jfinal.render.MyRenderFactory;
import com.ipan.jfinal.ui.ruoyi.PageDomain;
import com.ipan.kits.mapper.FastJsonMapper;
import com.ipan.kits.text.StrFormatter;
import com.jfinal.core.Controller;
import com.jfinal.core.NotAction;
import com.jfinal.kit.Kv;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.render.RenderManager;

/**
 * 简单的API接口通信基类
 * 
 * 支持对Http正文的返回内容统一加密，必须配合SimpleApiInterceptor同时使用！
 * 
 * 特殊属性名：
 * 	userId，用户ID；
 * 	appkey，用户APPKEY；
 * 	orgCusSendID，请求流水号；
 * 	reqData，请求参数（列表或对象）；
 * 
 * @author iPan
 * @date 2022-07-01
 */
public abstract class SimpleApiController extends Controller {
	protected int defaultPageSize = 10;
	protected boolean encryptModel = false; // 加密模式（正文是否加密？） true 加密  false 明文
	protected boolean callLimitModel = false; // 调用次数是否限制模式（是否限制次数？） true 限制 false 不限制
	private static final String ENCRYPT_RESULT_FMT = "{\"data\":\"{}\"}"; // 加密返回格式
	protected Log log = Log.getLog(this.getClass());
	protected boolean retState = false; // 业务执行是否成功 true 成功 false 失败，主要提供给拦截器使用；
	protected int calls = 0; // 接口调用次数
	protected int maxCalls = 0; // 接口调用最大次数
	private FastJsonMapper jsonNullMapper = FastJsonMapper.me().createWriteNullMapper(); // 必须支持输出null值
	
	@NotAction
	public boolean getEncryptModel() {
		return encryptModel;
	}
	@NotAction
	public boolean getCallLimitModel() {
		return callLimitModel;
	}
	@NotAction
	public boolean getRetState() {
		return retState;
	}
	@NotAction
	public void setRetState(boolean retState) {
		this.retState = retState;
	}
	@NotAction
	public int getCalls() {
		return calls;
	}
	@NotAction
	public void setCalls(int calls) {
		this.calls = calls;
	}
	@NotAction
	public int getMaxCalls() {
		return maxCalls;
	}
	@NotAction
	public void setMaxCalls(int maxCalls) {
		this.maxCalls = maxCalls;
	}
	
	/**
	 * 获取接口userId
	 */
	@NotAction
	public String getApiUserId() {
		return getAttr("userId");
	}
	/**
	 * 获取接口appkey
	 */
	@NotAction
	public String getApiAppkey() {
		return getAttr("appkey");
	}
	/**
	 * 获取接口orgCusSendID
	 */
	@NotAction
	public String getApiOrgCusSendID() {
		return getAttr("orgCusSendID");
	}
	
	/**
	 * 内容加密
	 */
	@NotAction
	public String encrypt(String input) {
		SimpleApiEncryptAble encrypter = SimpleApiManager.getEncrypter();
		String appkey = getApiAppkey();
		String text = encrypter.encrypt(input, appkey);
		return text;
	}
	
	/**
	 * 内容解密
	 */
	@NotAction
	public String decrypt(String input) {
		SimpleApiEncryptAble encrypter = SimpleApiManager.getEncrypter();
		String appkey = getApiAppkey();
		String text = encrypter.decrypt(input, appkey);
		return text;
	}
	
	/**
	 * 根据字符串生成模板输出string
	 */
	@NotAction
	public String renderToStrByStrTemplate(String content, Map data) {
		return RenderManager.me().getEngine().getTemplateByString(content).renderToString(data);
	}
	@NotAction
	public String renderToStrByStrTemplate(String content) {
		Map data = getRequest().getParameterMap();
		return RenderManager.me().getEngine().getTemplateByString(content).renderToString(data);
	}
	@NotAction
	public void renderImage(File file) {
		MyRenderFactory mf = (MyRenderFactory) RenderManager.me().getRenderFactory();
		render(mf.getImageRender(file));
	}
	@NotAction
	public void renderImage(String filePath) {
		MyRenderFactory mf = (MyRenderFactory) RenderManager.me().getRenderFactory();
		render(mf.getImageRender(new File(filePath)));
	}
	/**
	 * JWT版验证码，key放在http head里面；
	 */
	@NotAction
	public void renderHeadCaptcha() {
		MyRenderFactory mf = (MyRenderFactory) RenderManager.me().getRenderFactory();
		render(mf.getHeadCaptchaRender());
	}
	@NotAction
	public void renderTextFile(String text, String downloadFileName) {
		MyRenderFactory mf = (MyRenderFactory) RenderManager.me().getRenderFactory();
		render(mf.getTextFileRender(text, downloadFileName));
	}
	@NotAction
	public void renderTextFile(String text, String downloadFileName, String contentType, String encode) {
		MyRenderFactory mf = (MyRenderFactory) RenderManager.me().getRenderFactory();
		render(mf.getTextFileRender(text, downloadFileName, contentType, encode));
	}
	@NotAction
	public boolean validateHeadCaptcha(String paraName) {
		return MyCaptchaRender.validate(this, getPara(paraName));
	}
	
	//-- 渲染Json支持加密 --//
	@NotAction
	public void renderEncryptJson(String jsonText) {
		if (encryptModel) {
			String encryptJson = StrFormatter.format(ENCRYPT_RESULT_FMT, encrypt(jsonText));
			renderJson(encryptJson); // 为了让调用者的系统能够通过框架解析Json，直接返回加密字符串的话，可能框架会不支持！
		} else {
			renderJson(jsonText);
		}
	}
	@NotAction
	public void renderEncryptJson(Object object) {
		String jsonText = jsonNullMapper.toJson(object);
		renderEncryptJson(jsonText);
	}
	
	// --- 前端UI封装 --- //
	@NotAction
	public Kv pageToData(Page<?> page) {
		if (page == null) {
			return null;
		}
		ResultDefineManager rdm = ResultDefineManager.me();
		Kv result = Kv.by(rdm.getCodeKey(), rdm.getSuccess().getLeft())
			.set(rdm.getMsgKey(), rdm.getSuccess().getRight())
			.set(rdm.getTotalKey(), page.getTotalRow())
			.set(rdm.getRowsKey(), page.getList());
		return result;
	}
	@NotAction
	public Kv listToData(List<?> list) {
		if (list == null) {
			return null;
		}
		ResultDefineManager rdm = ResultDefineManager.me();
		Kv result = Kv.by(rdm.getCodeKey(), rdm.getSuccess().getLeft())
			.set(rdm.getMsgKey(), rdm.getSuccess().getRight())
			.set(rdm.getTotalKey(), list.size())
			.set(rdm.getRowsKey(), list);
		return result;
	}
	@NotAction
	public PageDomain buildPageDomain() { // 前端提交的分页参数
		ResultDefineManager rdm = ResultDefineManager.me();
		PageDomain pageDomain = new PageDomain();
        pageDomain.setPageNum(getInt(rdm.getPageNum()));
        pageDomain.setPageSize(getInt(rdm.getPageSize()));
        pageDomain.setOrderByColumn(getPara(rdm.getOrderByColumn()));
        pageDomain.setIsAsc(getPara(rdm.getIsAsc()));
        return pageDomain;
	}
	
	@NotAction
	public Kv retOk() {
		return retOk(ResultDefineManager.me().getSuccess().getRight(), null);
	}
	@NotAction
	public Kv retOk(String msg) {
		return retOk(msg, null);
	}
	@NotAction
	public Kv retOkData(Object data) {
		return retOk(ResultDefineManager.me().getSuccess().getRight(), data);
	}
	@NotAction
	public Kv retOk(String msg, Object data) { // 若retObj是Map，前端不支持包装成result对象，那么，需要自行处理！
		retState = true;
		ResultDefineManager rdm = ResultDefineManager.me();
		Kv ret = Kv.by(rdm.getCodeKey(), ResultDefineManager.me().getSuccess().getLeft())
				.set(rdm.getMsgKey(), (msg != null && msg.length() > 0) ? msg : ResultDefineManager.me().getSuccess().getRight()); // 0是成功，前端layui默认0是成功；
		if (data != null) {
			ret.set("data", data);
		}
		initCallsInfo(ret);
		return ret;
	}
	
	@NotAction
	public Kv retOkNoCallsInfo() { // 为了适应支持调用次数的控制器中使用不要次数控制的方法
		return retOkNoCallsInfo(ResultDefineManager.me().getSuccess().getRight(), null);
	}
	@NotAction
	public Kv retOkNoCallsInfo(String msg) {
		return retOkNoCallsInfo(msg, null);
	}
	@NotAction
	public Kv retOkDataNoCallsInfo(Object data) {
		return retOkNoCallsInfo(ResultDefineManager.me().getSuccess().getRight(), data);
	}
	@NotAction
	public Kv retOkNoCallsInfo(String msg, Object data) {
		retState = true;
		ResultDefineManager rdm = ResultDefineManager.me();
		Kv ret = Kv.by(rdm.getCodeKey(), ResultDefineManager.me().getSuccess().getLeft())
				.set(rdm.getMsgKey(), (msg != null && msg.length() > 0) ? msg : ResultDefineManager.me().getSuccess().getRight()); // 0是成功，前端layui默认0是成功；
		if (data != null) {
			ret.set("data", data);
		}
		return ret;
	}
	
	@NotAction
	public Kv retFail() {
		return retFail(ResultDefineManager.me().getFail().getLeft(), ResultDefineManager.me().getFail().getRight());
	}
	@NotAction
	public Kv retFail(String msg) {
		return retFail(ResultDefineManager.me().getFail().getLeft(), msg);
	}
	@NotAction
	public Kv retFail(String code, String msg) {
		retState = false;
		ResultDefineManager rdm = ResultDefineManager.me();
		Kv kv = Kv.by(rdm.getCodeKey(), code).set(rdm.getMsgKey(), msg);
		initCallsInfo(kv);
		return kv;
	}
	
	@NotAction
	public Kv retFailNoCallsInfo() { // 为了适应支持调用次数的控制器中使用不要次数控制的方法
		return retFailNoCallsInfo(ResultDefineManager.me().getFail().getLeft(), ResultDefineManager.me().getFail().getRight());
	}
	@NotAction
	public Kv retFailNoCallsInfo(String msg) {
		return retFailNoCallsInfo(ResultDefineManager.me().getFail().getLeft(), msg);
	}
	@NotAction
	public Kv retFailNoCallsInfo(String code, String msg) {
		retState = false;
		ResultDefineManager rdm = ResultDefineManager.me();
		Kv kv = Kv.by(rdm.getCodeKey(), code).set(rdm.getMsgKey(), msg);
		return kv;
	}
	
	@NotAction
	public void setResponseHead(String key, String value) {
		getResponse().setHeader(key, value);
	}
	@NotAction
	public void addResponseHead(String key, String value) {
		getResponse().addHeader(key, value);
	}
	@NotAction
	public void initCallsInfo(Kv kv) {
		if (callLimitModel) {
			kv.put("calls", calls);
			kv.put("maxCalls", maxCalls);
		}
	}
}